#include "FileSystem.h"
#include <stdlib.h>
#include <stdio.h>
#include <dirent.h>
#include <string.h>
#include <sys/stat.h>
#include <unistd.h>
struct FileSystem
{
    char *dirPath;
};

// 初始化一个文件系统对象
// 如果指定路径的目录不存在，则创建该目录。最后，返回指向文件系统对象的指针
FileSys * FileSystemInit(const char * DirPath)
{
    FileSys* fs = (FileSys* )malloc(sizeof(DirPath));
    if(fs == NULL)
    {
        printf("FileSystemInit malloc error!\n");
    }

    DIR *dir;
    //打开指定路径 DirPath 的目录
    if( (dir = opendir(DirPath)) == NULL)
    {
        if(mkdir(DirPath,0777) != 0)
        {
            perror("mkdir");
            free(fs);
            return NULL;
        }
        //将目录路径复制到 fs 结构体的 dirPath
        fs->dirPath = strdup(DirPath);
        return fs;
    }
    else
    {
        //如果目录已经存在，则关闭目录流
        closedir(dir);
        fs->dirPath = strdup(DirPath);
        return fs;
    }
}

//在文件系统中创建一个新的目录
bool CreateNewDirInFs(FileSys * fs, const char * DirName)
{
    char DirPath[1024] = {0};
    //将文件系统路径 fs->dirPath 和目录名称 DirName 拼接成完整的目录路径
    sprintf(DirPath,"%s/%s",fs->dirPath,DirName);
    if(mkdir(DirPath,0777) != 0)
    {
        perror("mkdir");
        return false;
    }
    return true;
}

//删除文件系统中指定路径下的目录
bool DeleteDirInFs(FileSys * fs, const char * DirName)
{
    char DirPath[1024] = {0};
    sprintf(DirPath,"%s/%s",fs->dirPath,DirName);
    if(rmdir(DirPath) != 0)
    {
        perror("rmdir");
        return false;
    }
    return true;
}

// 判断文件系统中是否存在指定路径的目录
bool isDirExist(FileSys * fs, const char * DirName)
{
    DIR *dir = opendir(fs->dirPath);
    if(dir == NULL)
    {
        perror("isDirExist opendir");
        return false;
    }

    struct dirent * entry;
    //遍历目录中的条目
    while( (entry = readdir(dir)) != NULL)
    {
        // 将每个条目的名称与目标目录名 DirName 进行比较
        if(strcmp(entry->d_name, DirName) == 0)
        {
            closedir(dir);
            return true;
        }
    }
    closedir(dir);
    return false;
}

//将给定的数据写入到文件系统的指定目录中的指定文件中
//一个指向 FileSys 结构体的指针 fs，一个指向目录名称的字符串指针 DirName，一个指向文件名的字符串指针 fileName，一个指向要写入文件的数据的指针 p，以及要写入的数据大小 size
void WriteFileToFs(FileSys *fs,const char * DirName,const char *fileName,void *p,size_t size)
{
    char filePath[1024] = {0};
    sprintf(filePath,"%s/%s",fs->dirPath,fileName);
    FILE * f = fopen(filePath,"a");//以追加模式打开文件路径 filePath ：追加模式意味着如果文件不存在，则会创建该文件；如果文件已经存在，则会将写入的内容添加到文件末尾
    fwrite(p,size,1,f);//将数据 p 写入文件 f，数据大小为 size，写入次数为 1
    fclose(f);//确保数据写入完成并释放资源
}


//filesysterm.c 计算文件大小 参数:1网盘用户目录 参数2:文件名 返回字符串形式大小
char *GetFileSize(const char *DirPath,const char *filename)
{
    char filePath[1024] = {0};
    sprintf(filePath,"%s/%s",DirPath,filename);

    struct stat st;
    stat(filePath,&st);//获取文件的元数据（包括文件大小）并存储在 st 结构体中

    char size[20] = {0};
    sprintf(size,"%ld",st.st_size);//将 st.st_size 转换为字符串，并存储在 size 中
    return strdup(size);
}

// 获取指定目录中的文件列表及其大小 并返回
char *GetFileList(FileSys *fs, const char *DirName)
{
    char list[1024] = {0};//文件列表
    char DirPath[1024] = {0};//服务器用户目录完整路径
    sprintf(DirPath,"%s/%s",fs->dirPath,DirName);// 构建完整目录路径
    DIR *dir = opendir(DirPath);
    if (dir == NULL)//若目录为空
    {
        return NULL;
    }
    struct dirent *entry;
    while((entry = readdir(dir)) != NULL)
    {
        //过滤隐藏目录
        if(strcmp(entry->d_name,".") == 0 || strcmp(entry->d_name,"..") == 0)
        {
            continue;
        }
        
        char *size = GetFileSize(DirPath,entry->d_name);

        strcat(list,entry->d_name);// 将文件名添加到列表中
        strcat(list,";");//文件大小以；分隔
        strcat(list,size);// 将文件大小添加到列表中
        strcat(list,",");
        free(size);
    }
    if (strlen(list) == 0)
    {
        return NULL;
    }
    list[strlen(list) - 1] = '\0';//去除最后的逗号
    closedir(dir);
    return strdup(list);
}

// 获取服务器上特定用户的特定文件的完整路径
char *GetServerFileDirPath(FileSys *fs, const char *username, const char *filename)
{
    char filePath[32] = {0};// 用于存储文件路径
    sprintf(filePath,"%s/%s/%s",fs->dirPath,username,filename);// 构建完整文件路径
    return strdup(filePath);
}
